#ifndef __COMMON_HPP__
#define __COMMON_HPP__

#include <cstdio>
#include <cstdlib>
#include <climits>
//#include <ctypes.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <getopt.h>

#include <set>
#include <map>
#include <vector>
#include <iostream>
#include <string>
#include <sstream>

#include "utils/utils.hpp"
#include "ipc/ipc.hpp"

#ifndef PERMITS
	#define PERMITS 0666
#endif
#ifndef MAX_LLENADORAS
	#define MAX_LLENADORAS 5
#endif

// Para simplificar la creacion de objetos IPC.
enum eBotellas { VACIAS = 1, LLENAS, TAPADAS, ETIQUETADAS, LISTAS };

#define SYNC (LISTAS+1)

enum eMaquinas { TAPADORA = 8, ETIQUETADORA, TRANSPORTADORA_A, REPOSITOR, AZUCARADORA_0, LLENADORA_0 = 32};
// LLENADORA_0 se utiliza para el semaforo y para identificar la boca 0.
// LLENADORA_0+i se utiliza para identificar las bocas.
// AZUCARADORA_0 idem LLENADORA_0 pero para las bocas que aportar azucar.

// Marca de que corresponde a un semaforo mutex.
#define MUTEX 64
// Marca de que corresponde a una variable compartida utilizada como contador.
#define COUNTER 128
// Marca de que corresponde a una cola de mensajes.
#define MSG_QUEUE 192

// Usado como identificador de mensaje de entrada.
#define PEDIR_RECURSO 1

enum eEstado { VACIA, LLENA, TAPADA, ETIQUETADA, COMPLETA };

std::string eEstadoToStr(int estado) {
	std::string aux;
	switch (estado) {
		case VACIA: aux= "Vacia"; break;
		case LLENA: aux= "Llena"; break;
		case TAPADA: aux= "Tapada"; break;
		case ETIQUETADA: aux= "Etiquetada"; break;
		case COMPLETA: aux= "Completa"; break;
		default: break;
	}
	return aux;
}

typedef struct {
	long tipo;
	eEstado estado;
	size_t id;
} sBotella;

// Representación del pedido de un recurso dado.
enum eRecurso { NINGUNO, BOTELLA, JUGO, TAPA, ETIQUETA, AZUCAR, JUGO_SIN_AZUCAR };
typedef struct {
	long tipo;
	pid_t origen;
	eRecurso recurso;
	key_t sem_key;
	size_t sem_num;
} sPedido;

typedef struct {
	long tipo;
	eRecurso recurso;
	size_t cantidad;
} sReposicion;

// Token para sincronización.
typedef struct {
	long tipo;
	size_t esperando;
} sToken;

// Discriminantes para los tipos de mensajes utilizados en las colas.
//enum eMensajeTipo { CUALQUIERA = 0, SBOTELLA_TIPO, SRECURSO_TIPO};

inline key_t my_ftok(int value) {
	return ftok(BASE_NAME,value);
//	key_t k = ftok(BASE_NAME,value);
//	if (k == (key_t)-1)
//		throw ipc::exception("ftok");
}

std::string eRecursoToStr(int recurso) {
	std::string aux;
	switch (recurso) {
		case NINGUNO:	aux = "Ninguno"; break;
		case BOTELLA:	aux = "Botella"; break;
		case JUGO:	aux = "Jugo"; break;
		case TAPA:	aux = "Tapa"; break;
		case ETIQUETA:	aux = "Etiqueta"; break;
		case AZUCAR:	aux = "Azucar"; break;
		case JUGO_SIN_AZUCAR: aux = "Jugo sin azucar"; break;
		default: break;
	}
	return aux;
}

std::string eMaquinasToStr(int maquina) {
	std::string aux;
	switch (maquina) {
		case TAPADORA: 	aux = "Tapadora"; break;
		case ETIQUETADORA:	aux = "Etiquetadora" ; break;
		case TRANSPORTADORA_A: aux = "Transportadora de botellas vacias"; break;
		case REPOSITOR: aux = "Repositor"; break;
		default: break;
	};
	if ( aux.empty() && (maquina && LLENADORA_0) ) {
		aux = "Llenadora ";
		aux+= (char)('0'+maquina-LLENADORA_0);
	}
	return aux;
}

#define SIMULAR_LLENAR	 usleep( rand()%3000 + 1000 )
#define SIMULAR_TAPAR	 usleep( rand()%100 + 100 )
#define SIMULAR_ETIQUETAR usleep( rand()%100 + 100 )

static utils::logger_stream logger (stdout);
static utils::logger_stream error (stdout,' ',"\033[1;31m");

//static utils::no_log logger;

#define nl utils::nl

//static utils::assert<ipc::exception> assert;

#endif /* __COMMON_HPP__ */

